package com.skyblue.statemachine.config;

import java.util.EnumSet;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.statemachine.StateMachine;
import org.springframework.statemachine.config.StateMachineBuilder;
import org.springframework.stereotype.Component;

/**
 * 复杂订单状态机构建器
 */
@Component
public class ComplexFormStateMachineBuilder {

    private final static String MACHINE_ID = "complexFormMachine";

    /**
     * 构建状态机
     */
    public StateMachine<ComplexFormStates, ComplexFormEvents> build(BeanFactory beanFactory) throws Exception {
        StateMachineBuilder.Builder<ComplexFormStates, ComplexFormEvents> builder = StateMachineBuilder.builder();

        System.out.println("构建复杂表单状态机");

        builder.configureConfiguration()
                .withConfiguration()
                .machineId(MACHINE_ID)
                .beanFactory(beanFactory);

        builder.configureStates()
                .withStates()
                .initial(ComplexFormStates.BLANK_FORM)
                .choice(ComplexFormStates.CHECK_CHOICE)
                .choice(ComplexFormStates.DEAL_CHOICE)
                .states(EnumSet.allOf(ComplexFormStates.class));

        builder.configureTransitions()
                /*用于定义外部状态转换（External Transition）
                特点：触发转换时，会先退出源状态，再进入目标状态
                典型场景：订单从"待支付"到"已支付"的状态转换*/
                .withExternal()
                .source(ComplexFormStates.BLANK_FORM).target(ComplexFormStates.FULL_FORM)
                .event(ComplexFormEvents.WRITE)
                .and()
                /**
                 * ‌不改变当前状态‌：与withExternal()不同，内部转换不会退出源状态或进入目标状态
                 * 触发条件‌：仍需要指定事件（Event）作为触发条件
                 * 执行顺序‌：仅执行关联的action()和guard()，不触发状态进入/退出监听
                 * ‌状态自更新‌：当状态需要维护内部数据但不改变状态标识时
                 * 必须同时指定source()和event()，否则配置无效
                 * 内部转换的action()中修改的上下文数据会持久化
                 */
                .withInternal()
                .source(ComplexFormStates.FULL_FORM)
                .event(ComplexFormEvents.WRITE)
                .guard((context) -> true)
                .action((context) -> System.out.println("填写表单"))
                .and()
                .withExternal()
                .source(ComplexFormStates.FULL_FORM).target(ComplexFormStates.CHECK_CHOICE)
                .event(ComplexFormEvents.CHECK)
                .and()
                /*用于创建选择节点（Choice Pseudostate）
                特点：根据条件判断决定下一个状态
                需要配合.first()、.then()和.last()方法使用
                典型场景：根据支付金额决定走不同流程分支*/
                .withChoice()
                .source(ComplexFormStates.CHECK_CHOICE)
                // first-guard-条件 == true 进入 CONFIRM_FORM 并执行 first-action，false 进入 then 的 guard-条件判断
                .first(ComplexFormStates.CONFIRM_FORM, new ComplexFormCheckChoiceGuard(), new ComplexFormChoiceAction())
                // then-guard-条件 == true 进入 MID_FORM 并执行 then-action，false 直接进入 last 的 DEAL_FORM 并执行 last-action
                .then(ComplexFormStates.MID_FORM, new ComplexFormCheckChoiceGuard(), new ComplexFormChoiceAction())
                .last(ComplexFormStates.DEAL_FORM, new ComplexFormChoiceAction())
                .and()
                .withExternal()
                .source(ComplexFormStates.CONFIRM_FORM).target(ComplexFormStates.SUCCESS_FORM)
                .event(ComplexFormEvents.SUBMIT)
                .and()
                .withExternal()
                .source(ComplexFormStates.DEAL_FORM).target(ComplexFormStates.DEAL_CHOICE)
                .event(ComplexFormEvents.DEAL)
                .and()
                .withChoice()
                .source(ComplexFormStates.DEAL_CHOICE)
                .first(ComplexFormStates.FULL_FORM, new ComplexFormDealChoiceGuard(), new ComplexFormChoiceAction())
                .last(ComplexFormStates.FAILED_FORM, new ComplexFormChoiceAction());
        return builder.build();
    }
}


